package edu.hawaii.myisern.action;

import java.math.BigInteger;
import java.util.List;
import edu.hawaii.myisern.collaborations.jaxb.CollaboratingOrganizations;
import edu.hawaii.myisern.collaborations.jaxb.Collaboration;
import edu.hawaii.myisern.collaborations.jaxb.CollaborationTypes;
import edu.hawaii.myisern.collaborations.jaxb.OutcomeTypes;
import edu.hawaii.myisern.collaborations.jaxb.Years;
import edu.hawaii.myisern.model.ListStringConverter;
import edu.hawaii.myisern.model.MyIsernModel;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;


/**
 * Allows for a collaboration to be added or edited. 
 * 
 * @author Ed Kim
 * @author Jon Lao
 * @author JianFei Liao
 * @author Jared Sunouchi
 */
public class CollaborationActionBean implements ActionBean {
  /** Required by the ActionBean interface. */
  private ActionBeanContext context;
  /** An error string, always displayed, but invisible if empty. */
  private String errorMessage = "";
  /** Added? */
  private boolean added;
  /** Editing? */
  private boolean editing;
  /** Edited? */
  private boolean edited;
  /** The single MyIsern instance manipulated by all webapp users. */
  private MyIsernModel myIsern = MyIsernModel.getInstance();
  /** Collaboration attributes */
  private String name;
  private String collaboratingOrganizations;
  private String collaborationTypes;
  private String years;
  private String outcomeTypes;
  private String description;
  
  private String collaborationNamesList;
  private String organizationNamesList;
  
  private static final String ADD_COLLAB_PAGE = "/addCollaboration.jsp";
  private static final String EDIT_COLLAB_PAGE = "/editCollaboration.jsp";
  private static final String HOME_PAGE = "/home.jsp";
  
  /** A converter between list and objects. */
  private ListStringConverter converter = new ListStringConverter();
  
  /** Variable from jsp pages used to find organization */
  private String linkItem = " ";
  
  /**
   * Returns the context. Required by the interface. 
   * 
   * @return the ActionBeanContext.
   */
  public ActionBeanContext getContext() {
    return context;
  }
  
  /**
   * Sets the context. Required by the interface. 
   * 
   * @param context The ActionBeanContext to set. 
   */
  public void setContext(ActionBeanContext context) {
    this.context = context;
  }
  
  /**
   * Returns the error message, which may be empty.
   * Indicates if an error was made adding or editing the collaboration. 
   * 
   * @return The error message. 
   */
  public String getErrorMessage() {
    return this.errorMessage;
  }
  
  /**
   * Returns the whether the collaboration has been added or not.
   * 
   * @return Whether the collaboration has been added or not. 
   */
  public boolean getAdded() {
    return this.added;
  }
  
  /**
   * Returns the whether the collaboration has been edited or not.
   * 
   * @return Whether the collaboration has been edited or not. 
   */
  public boolean getEdited() {
    return this.edited;
  }
  
  /**
   * Returns the whether the collaboration is being edited or not.
   * 
   * @return Whether the collaboration is being edited or not. 
   */
  public boolean getEditing() {
    return this.editing;
  }
  
  /**
   * Returns the string representation that will be used to generate the javascript array.
   * 
   * @return The string representation that will be used to generate the javascript array. 
   */
  public String getCollaborationNamesList() {
    this.collaborationNamesList = myIsern.getCollaborationNamesList();
    return this.collaborationNamesList;
  }
  
  /**
   * Returns the string representation that will be used to generate the javascript array.
   * 
   * @return The string representation that will be used to generate the javascript array. 
   */
  public String getOrganizationNamesList() {
    this.organizationNamesList = myIsern.getOrganizationNamesList();
    return this.organizationNamesList;
  }
  
//  /**
//   * Displays the form to add a collaboration.
//   * 
//   * @return A Resolution indicating to redisplay the add.jsp page.
//   */
//  public Resolution collaborationForm() {
//    return new ForwardResolution(ADD_COLLAB_PAGE);
//  }
  
  /**
   * Displays the form to edit a collaboration.
   * 
   * @return A Resolution indicating to redisplay the edit.jsp page.
   */
  public Resolution editCollaborationForm() {
    return new ForwardResolution(EDIT_COLLAB_PAGE);
  }
  
  /**
   * Resets the collaboration data.
   */
  public void resetData() {
    this.setName("");
    this.setCollaboratingOrganizations("");
    this.setCollaborationTypes("");
    this.setYears("");
    this.setOutcomeTypes("");
    this.setDescription("");
  }
  
  /**
   * Clears the text in the text boxes.
   * 
   * @return A Resolution indicating to redirect to the add.jsp page.
   */
  public Resolution reset() {
    this.resetData();
    return new RedirectResolution(ADD_COLLAB_PAGE).flash(this);
  }
  
  /**
   * Clears the text in the text boxes.
   * 
   * @return A Resolution indicating to redirect to the home.jsp page.
   */
  public Resolution cancel() {
    return new RedirectResolution(HOME_PAGE);
  }
  
  /**
   * Sets the name of the collaboration.
   * 
   * @param name The name to set.
   */
  public void setName(String name) {
    this.name = name.trim();
  }
  
  /**
   * Returns the name of the collaboration.
   * 
   * @return The name of the collaboration.
   */
  public String getName() {
    return this.name;
  }
  
  /**
   * Sets the collaborating organizations of the collaboration.
   * 
   * @param collaboratingOrganizations  The collaborating organizations to set.
   */
  public void setCollaboratingOrganizations(String collaboratingOrganizations) {
    this.collaboratingOrganizations = collaboratingOrganizations;
  }
  
  /**
   * Returns the collaborating organizations of the collaboration.
   * 
   * @return The collaborating organizations of the collaboration.
   */
  public String getCollaboratingOrganizations() {
    return this.collaboratingOrganizations;
  }
  
  /**
   * Sets the collaboration types of the collaboration.
   * 
   * @param collaborationTypes  The collaboration types to set.
   */
  public void setCollaborationTypes(String collaborationTypes) {
    this.collaborationTypes = collaborationTypes;
  }
  
  /**
   * Returns the collaboration types of the collaboration.
   * 
   * @return The collaboration types of the collaboration.
   */
  public String getCollaborationTypes() {
    return this.collaborationTypes;
  }
  
  /**
   * Sets the years of the collaboration.
   * 
   * @param years The years to set.
   */
  public void setYears(String years) {
    this.years = years;
  }
  
  /**
   * Returns the years of the collaboration.
   * 
   * @return The years of the collaboration.
   */
  public String getYears() {
    return this.years;
  }
  
  /**
   * Sets the outcome types of the collaboration.
   * 
   * @param outcomeTypes The outcome types to set.
   */
  public void setOutcomeTypes(String outcomeTypes) {
    this.outcomeTypes = outcomeTypes;
  }
  
  /**
   * Returns the outcome types of the collaboration.
   * 
   * @return The outcome types of the collaboration.
   */
  public String getOutcomeTypes() {
    return this.outcomeTypes;
  }
  
  /**
   * Sets the description of the collaboration.
   * 
   * @param description The description to set.
   */
  public void setDescription(String description) {
    this.description = description.trim();
  }
  
  /**
   * Returns the description of the collaboration.
   * 
   * @return The description of the collaboration.
   */
  public String getDescription() {
    return this.description;
  }
  
  /**
   * Adds a collaboration.
   * 
   * @return A Resolution indicating to redisplay the add.jsp page.
   * @throws Exception If problems occur.
   */
  public Resolution add() throws Exception {
    if (this.name == null) {
      this.errorMessage = "Please enter a name.";
    }
    else {
      List<Collaboration> list = myIsern.getCollaborationsList();
      boolean found = false;
      for (Collaboration collaboration : list) {
        if (collaboration.getName().equals(this.name.replace('_', ' '))) {
          found = true;
        }
      }

      if (found) {
        this.errorMessage = "Collaboration already exists. Please edit instead.";
        this.editing = true;
        Collaboration collab = this.myIsern.getSingleCollaboration(this.name);
        this.collaboratingOrganizations = this.converter.listToString(collab
            .getCollaboratingOrganizations().getCollaboratingOrganization());
        this.collaborationTypes = this.converter
            .listToString(collab.getCollaborationTypes().getCollaborationType());
        this.years = this.converter.bigIntegerListToString(collab.getYears().getYear());
        this.outcomeTypes = this.converter.listToString(collab.getOutcomeTypes()
            .getOutcomeType());
        this.description = collab.getDescription();
        return new RedirectResolution(EDIT_COLLAB_PAGE).flash(this);
      }
      else {
        Collaboration newCollaboration = new Collaboration();
        newCollaboration.setName(this.name);
        // collaborating organizations
        if (this.collaboratingOrganizations == null) {
          this.errorMessage = "Collaborating organizations are required.";
          return this.getContext().getSourcePageResolution();
        }
        else {
          CollaboratingOrganizations newCollabOrgs = new CollaboratingOrganizations();
          List<String> tempList = this.converter.stringToList(collaboratingOrganizations);
          if (tempList.size() < 2) {
            this.errorMessage = "At least two collaborating organizations are required.";
            return this.getContext().getSourcePageResolution();
          }
          else {
            newCollabOrgs.getCollaboratingOrganization()
                .addAll(tempList);
            newCollaboration.setCollaboratingOrganizations(newCollabOrgs);
          }
        }
        // collaboration-types
        if (this.collaborationTypes == null) {
          this.errorMessage = "Collaboration types are required.";
          return this.getContext().getSourcePageResolution();
        }
        else {
          CollaborationTypes newCollaborationTypes = new CollaborationTypes();
          newCollaborationTypes.getCollaborationType()
              .addAll(this.converter.stringToList(collaborationTypes));
          newCollaboration.setCollaborationTypes(newCollaborationTypes);
        }
        // years
        if (this.years == null) {
          this.errorMessage = "Years are required.";
          return this.getContext().getSourcePageResolution();
        }
        else {
          List<BigInteger> yearsList = null;
          try {
            yearsList = this.converter.stringToBigIntegerList(this.years);
          }
          catch (NumberFormatException e) {
            this.errorMessage = "The years must be in number format.";
            return this.getContext().getSourcePageResolution();
          }
          for (BigInteger year : yearsList) {
            if (year.intValue() > 2010 || year.intValue() < 1990) {
              this.errorMessage = "The years must within the range of 1990 to 2010.";
              return this.getContext().getSourcePageResolution();
            }
          }
          Years newYears = new Years();
          newYears.getYear().addAll(this.converter.stringToBigIntegerList(this.years));
          newCollaboration.setYears(newYears);
        }
        // outcome types
        if (this.outcomeTypes == null) {
          this.errorMessage = "Outcome types are required.";
          return this.getContext().getSourcePageResolution();
        }
        else {
          OutcomeTypes newOutcomeTypes = new OutcomeTypes();
          newOutcomeTypes.getOutcomeType().addAll(this.converter.stringToList(this.outcomeTypes));
          newCollaboration.setOutcomeTypes(newOutcomeTypes);
        }
        // description
        newCollaboration.setDescription(this.description);

        myIsern.addOrEditCollaboration(newCollaboration);

        this.added = true;
      }
    }
    return new ForwardResolution(ADD_COLLAB_PAGE);
  }
  
  /**
   * Displays the information to edit.
   * 
   * @return A resolution indicating to redisplay the edit.jsp page.
   * @throws Exception If problems occur.
   */
  public Resolution displayEdit() throws Exception {
    List<Collaboration> list = myIsern.getCollaborationsList();
    Collaboration editCollaboration = new Collaboration();
    boolean found = false;
    for (Collaboration collaboration : list) {
      if (collaboration.getName().equals(this.name.replace('_', ' '))) {
        editCollaboration = collaboration;
        found = true;
      }
    }

    if (found) {
      this.collaboratingOrganizations = this.converter.listToString(editCollaboration
          .getCollaboratingOrganizations().getCollaboratingOrganization());
      this.collaborationTypes = this.converter
          .listToString(editCollaboration.getCollaborationTypes().getCollaborationType());
      this.years = this.converter.bigIntegerListToString(editCollaboration.getYears().getYear());
      this.outcomeTypes = this.converter.listToString(editCollaboration.getOutcomeTypes()
          .getOutcomeType());
      this.description = editCollaboration.getDescription();

      this.editing = true;
    }
    return new ForwardResolution(EDIT_COLLAB_PAGE);
  }
  
  /**
   * Edits a collaboration.
   * 
   * @return A resolution indicating to redisplay the edit.jsp page.
   * @throws Exception If problems occur.
   */
  public Resolution edit() throws Exception {
    List<Collaboration> list = myIsern.getCollaborationsList();
    Collaboration editCollaboration = new Collaboration();
    for (Collaboration collaboration : list) {
      if (collaboration.getName().equals(this.name.replace('_', ' '))) {
        editCollaboration = collaboration;
      }
    }
    
    // collaborating organizations
    if (this.collaboratingOrganizations == null) {
      this.errorMessage = "Collaborating organizations are required.";
      this.editing = true;
      return this.getContext().getSourcePageResolution();
    }
    else {
      CollaboratingOrganizations newCollaboratingOrganizations = new CollaboratingOrganizations();
      List<String> tempList = this.converter.stringToList(collaboratingOrganizations);
      if (tempList.size() < 2) {
        this.errorMessage = "At least two ollaborating organizations are required.";
        this.editing = true;
        return this.getContext().getSourcePageResolution();
      }
      else {
        newCollaboratingOrganizations.getCollaboratingOrganization()
            .addAll(tempList);
        editCollaboration.setCollaboratingOrganizations(newCollaboratingOrganizations);
      }
    }
    // collaboration-types
    if (this.collaborationTypes == null) {
      this.errorMessage = "Collaboration types are required.";
      this.editing = true;
      return this.getContext().getSourcePageResolution();
    }
    else {
      CollaborationTypes newCollaborationTypes = new CollaborationTypes();
      newCollaborationTypes.getCollaborationType()
          .addAll(this.converter.stringToList(collaborationTypes));
      editCollaboration.setCollaborationTypes(newCollaborationTypes);
    }
    // years
    if (this.years == null) {
      this.errorMessage = "Years are required.";
      this.editing = true;
      return this.getContext().getSourcePageResolution();
    }
    else {
      List<BigInteger> yearsList = null;
      try {
        yearsList = this.converter.stringToBigIntegerList(this.years);
      }
      catch (NumberFormatException e) {
        this.errorMessage = "The years must be in number format.";
        return this.getContext().getSourcePageResolution();
      }
      for (BigInteger year : yearsList) {
        if (year.intValue() > 2010 || year.intValue() < 1990) {
          this.errorMessage = "The years must within the range of 1990 to 2010.";
          return this.getContext().getSourcePageResolution();
        }
      }
      Years newYears = new Years();
      newYears.getYear().addAll(this.converter.stringToBigIntegerList(this.years));
      editCollaboration.setYears(newYears);
    }
    // outcome types
    if (this.outcomeTypes == null) {
      this.errorMessage = "Outcome types are required.";
      this.editing = true;
      return this.getContext().getSourcePageResolution();
    }
    else {
      OutcomeTypes newOutcomeTypes = new OutcomeTypes();
      newOutcomeTypes.getOutcomeType().addAll(this.converter.stringToList(this.outcomeTypes));
      editCollaboration.setOutcomeTypes(newOutcomeTypes);
    }
    // description
    editCollaboration.setDescription(this.description);
    
    myIsern.addOrEditCollaboration(editCollaboration);
    
    this.edited = true;
    this.editing = true;
    return new ForwardResolution(EDIT_COLLAB_PAGE);
  }
  
  /**
   * Removes the collaboration.
   * 
   * @return A resolution indicating to redisplay the add.jsp or edit.jsp page.
   * @throws Exception If problems occur.
   */
  public Resolution remove() throws Exception {    
    myIsern.removeCollaboration(this.name);
    
    this.errorMessage = this.name + " has been removed.";
    return new ForwardResolution(ADD_COLLAB_PAGE);
  }
  
  /**
   * Sets the link item variable from jsp pages.
   * 
   * @param string The new invalid organization link.
   */
  public void setLinkItem(String string) {
    this.linkItem = string;
  }
  
  /**
   * Finds the organization by name from jsp link item variable.
   * Redirects to Add organization if it doesn't exist or
   * Edit organization if it does.
   * 
   * @return resolution either to editing or adding the organization.
   */
  public Resolution linkToCollaboration() {
   Collaboration c = this.myIsern.getSingleCollaboration(this.linkItem);
   if (c == null) {
     this.name = this.linkItem;
     this.added = false;
     return new RedirectResolution(ADD_COLLAB_PAGE).flash(this);
   }
   else {
     this.name = this.linkItem;
     
     this.collaboratingOrganizations = 
       this.converter.listToString(c.getCollaboratingOrganizations().
           getCollaboratingOrganization());

     this.collaborationTypes =
       this.converter.listToString(c.getCollaborationTypes().getCollaborationType());
     
     this.years = this.converter.bigIntegerListToString(c.getYears().getYear());
     
     this.outcomeTypes = 
       this.converter.listToString(c.getOutcomeTypes().getOutcomeType());
    
     this.description = c.getDescription();
     
     this.edited = false;
     this.editing = true;
     return new RedirectResolution(EDIT_COLLAB_PAGE).flash(this);
   }
 }  
}